package com.buercorp.wangyu.buerhashmap;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Set;

import static java.util.Objects.hash;

/***
 * map接口的实现
 * @author wangyu
 * @date
 * @param <K>
 * @param <V>
 */
public class BuerHashMap<K, V> implements Map<K, V> {
    transient int size;
    Entry<K, V>[] table = null;

    /***
     * 初始容量 1 << 4
     * 加载因子 0.75f
     */
    public BuerHashMap() {
        table = new Entry[16];
    }

    @Override
    public int size() {
        return size;
    }

    /***
     * key进行hash 取模算出index 下标
     * 数组的对应节点对象 对象是否为空
     * 如果为空 复制存储
     * 如果不为空 冲突 链表存储
     * 返回值
     * @return
     */
    @Override
    public V put(K k, V v) {
        int index = hash(k);
        Entry<K, V> entry = table[index];
        if (entry == null) {
            table[index] = new Entry<>(k, v, index, null);
            size++;
        } else {
            table[index] = new Entry<>(k, v, index, entry);
        }
        return table[index].getValue();
    }

    /***
     * 算出hashcode 取模得到下标 计算得到index 幂等性
     * 源码：int h; hash值
     *       return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
     * @param k
     * @return
     */
    private int hash(K k) {
        int index = k.hashCode() % 16;
        return index > 0 ? index : -index;
    }

    /***
     * key 进行hash index下标
     * 是否为空 如果为空 直接返回 null
     * 不为空 查询k 与 当前k 进行比较
     * 如果相等 直接返回数据
     * 如果不相等 next是否为空
     * 如果为空 直接返回
     * 如果不为空
     * k 是否与key 相等 直到相等为止
     * @param k
     * @return
     */
    @Override
    public V get(K k) {
        int index = hash(k);
        Entry<K, V> entry = findValue(table[index], k);
        return entry == null ? null : table[index].getValue();
    }

    /***
     * 递归调用
     * @param entry
     * @param k
     * @return
     */
    public Entry<K, V> findValue(Entry<K, V> entry, K k) {
        if (k.equals(entry.getKey()) || k == entry.getKey()) {
            return entry;
        } else {
            if (entry.next != null) {
                return findValue(entry.next, k);
            }
        }
        return null;
    }

    /***
     * 首先，计算要删除的键的哈希值，并确定其在数组中的索引位置。
     * 然后，遍历该索引位置的链表，查找与要删除的键相等的节点。
     * 如果找到了与要删除的键相等的节点，将其从链表中删除，并更新HashMap的大小。
     * 如果没有找到与要删除的键相等的节点，说明该键不存在于HashMap中，直接返回null。
     * 最后，返回被删除节点的值。
     * @param k
     * @return
     */
    @Override
    public V delete(K k) {
        int index = hash(k);
        Entry<K, V> entry = findValue(table[index], k);
        if (entry == null) {
            return null;
        } else {
            V deleteValue = entry.getValue();
            if (entry.next != null) {
                entry.v = entry.next.v;
                entry.k = entry.next.k;
                entry.next = entry.next.next;
            } else {
                table[index] = null;
            }
            size--;
            return deleteValue;
        }
    }

    /**
     * 每个Entry对象都包含了一个键（key）和一个值（value）
     *
     * @param <K>
     * @param <V>
     */
    class Entry<K, V> implements Map.Entry<K, V> {
        K k;
        V v;
        int index;
        Entry<K, V> next;

        public Entry(K k, V v, int index, Entry<K, V> next) {
            this.k = k;
            this.v = v;
            this.index = index;
            this.next = next;
        }

        @Override
        public K getKey() {
            return k;
        }

        @Override
        public V getValue() {
            return v;
        }
    }
}
